/*
 * #%L
 * SwiftUICommonUtilities
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2012 Linkwithweb
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */
package com.linkwithweb.products.swiftui.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRMapCollectionDataSource;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.export.JExcelApiExporter;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRTextExporter;
import net.sf.jasperreports.engine.export.JRTextExporterParameter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import net.sf.jasperreports.engine.xml.JRXmlLoader;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ClassPathResource;

public class ReportGenerator {
	protected final Log log = LogFactory.getLog(getClass());

	public final String EXTENSION_PDF = "pdf";
	public final String EXTENSION_TXT = "text";
	public final String EXTENSION_XML = "xml";
	public final String EXTENSION_HTML = "html";
	public final String EXTENSION_XLS = "xls";
	public final String EXTENSION_CSV = "csv";

	/**
	 * 
	 * @param jasperPrint
	 * @param exportLocation
	 * @param reportName
	 * @param fileExtension
	 */
	private void generatePDF(JasperPrint jasperPrint, String exportLocation,
			String reportName, String fileExtension, OutputStream outputStream) {
		try {
			// JasperExportManager.exportReportToPdfFile(jasperPrint,
			// exportLocation + File.separator + reportName + "."
			// + fileExtension);
			JasperExportManager.exportReportToPdfStream(jasperPrint,
					outputStream);
		} catch (JRException e) {
			e.printStackTrace();
			log.error(e.fillInStackTrace());
		}
	}

	/**
	 * 
	 * @param jasperPrint
	 * @param exportLocation
	 * @param reportName
	 * @param fileExtension
	 */
	private void generateHTML(JasperPrint jasperPrint, String exportLocation,
			String reportName, String fileExtension, OutputStream outputStream) {
		try {
			// JasperExportManager.exportReportToHtmlFile(jasperPrint,
			// exportLocation + File.separator + reportName + "."
			// + fileExtension);
			JRHtmlExporter htmlExporter = new JRHtmlExporter();
			htmlExporter.setParameter(JRExporterParameter.JASPER_PRINT,
					jasperPrint);
			htmlExporter.setParameter(JRExporterParameter.OUTPUT_STREAM,
					outputStream);
			htmlExporter.exportReport();
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.fillInStackTrace());
		}
	}

	/**
	 * 
	 * @param jasperPrint
	 * @param exportLocation
	 * @param reportName
	 * @param fileExtension
	 */
	private void generateXML(JasperPrint jasperPrint, String exportLocation,
			String reportName, String fileExtension, OutputStream outputStream) {
		try {
			// JasperExportManager.exportReportToXmlFile(jasperPrint,
			// exportLocation + File.separator + reportName + "."
			// + fileExtension, Boolean.TRUE);
			JasperExportManager.exportReportToXmlStream(jasperPrint,
					outputStream);

		} catch (JRException e) {
			e.printStackTrace();
			log.error(e.fillInStackTrace());
		}
	}

	/**
	 * 
	 * @param jasperPrint
	 * @param sheetName
	 * @param exportLocation
	 * @param reportName
	 * @param fileExtension
	 */
	private void generateXLS(JasperPrint jasperPrint, String sheetName,
			String exportLocation, String reportName, String fileExtension,
			OutputStream outputStream) {
		// JRXlsExporter exporter = new JRXlsExporter();
		JExcelApiExporter exporter = new JExcelApiExporter();
		exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
		exporter.setParameter(JRXlsExporterParameter.CHARACTER_ENCODING,
				"UTF-8");
		// File destFile = new File(exportLocation, reportName + "."
		// + fileExtension);
		// exporter.setParameter(JRExporterParameter.OUTPUT_FILE, destFile);
		exporter.setParameter(JRXlsExporterParameter.OUTPUT_STREAM,
				outputStream);
		exporter.setParameter(JRXlsExporterParameter.IS_IGNORE_CELL_BORDER,
				Boolean.TRUE);
		exporter.setParameter(
				JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
				Boolean.FALSE);
		exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND,
				Boolean.FALSE);
		exporter.setParameter(JRXlsExporterParameter.IGNORE_PAGE_MARGINS,
				Boolean.TRUE);
		exporter.setParameter(JRXlsExporterParameter.SHEET_NAMES,
				new String[] { sheetName });
		try {
			exporter.exportReport();
		} catch (JRException e) {
			e.printStackTrace();
			log.error(e.fillInStackTrace());
		}

	}

	/**
	 * 
	 * @param jasperPrint
	 * @param exportLocation
	 * @param reportName
	 * @param fileExtension
	 */
	private void generateTXT(JasperPrint jasperPrint, String exportLocation,
			String reportName, String fileExtension, OutputStream outputStream) {

		JRTextExporter textexp = new JRTextExporter();

		textexp.setParameter(JRTextExporterParameter.CHARACTER_WIDTH,
				new Integer(5));
		textexp.setParameter(JRTextExporterParameter.CHARACTER_HEIGHT,
				new Integer(8));
		textexp.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
		// File destFile = new File(exportLocation, reportName + "."
		// + fileExtension);
		// textexp.setParameter(JRExporterParameter.OUTPUT_FILE, destFile);
		textexp.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
		try {
			textexp.exportReport();
		} catch (JRException e) {
			e.printStackTrace();
			log.error(e.fillInStackTrace());
		}

	}

	/**
	 * 
	 * @param jasperPrint
	 * @param exportLocation
	 * @param reportName
	 * @param fileExtension
	 */
	private void generateCSV(JasperPrint jasperPrint, String exportLocation,
			String reportName, String fileExtension, OutputStream outputStream) {
		JRCsvExporter exporter = new JRCsvExporter();
		exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
		// File destFile = new File(exportLocation, reportName + "."
		// + fileExtension);
		// exporter.setParameter(JRExporterParameter.OUTPUT_FILE, destFile);
		exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
		try {
			exporter.exportReport();
		} catch (JRException e) {
			e.printStackTrace();
			log.error(e.fillInStackTrace());
		}

	}

	public String getSqlParameters(Map<String, Object> sqlParams) {
		StringBuffer params = new StringBuffer();
		for (Map.Entry<String, Object> entry : sqlParams.entrySet()) {
			params.append(entry.getKey()).append("=").append(entry.getValue())
					.append(" ");
		}
		return params.toString();

	}

	/**
	 * 
	 * @param reportTemplateFile
	 * @return
	 */
	private JasperReport compileReport(String reportTemplateFile) {

		JasperReport report = null;
		try {
			InputStream stream = new ClassPathResource(reportTemplateFile).getInputStream();
			JasperDesign design = JRXmlLoader.load(stream);
			report = JasperCompileManager.compileReport(design);
		} catch (IOException e) {

			log.error(e.fillInStackTrace());
		} catch (JRException e) {

			log.error(e.fillInStackTrace());
		}

		return report;
	}

	/**
	 * 
	 * @param jasperReport
	 * @param filedsSet
	 * @param reportData
	 * @param parameters
	 * @return
	 */
	private JasperPrint getJasperPrintObjectForFields(JasperReport jasperReport, String[] filedsSet, List reportData, HashMap<String, Object> parameters) {
		HibernateQueryResultDataSource ds = new HibernateQueryResultDataSource(reportData, filedsSet);
		JasperPrint print = null;
		try {
			print = JasperFillManager.fillReport(jasperReport, parameters, ds);
		} catch (JRException e) {

			log.error(e.fillInStackTrace());
		}
		return print;
	}

	/**
	 * 
	 * @param portfolioName
	 * @param reportTemplateFile
	 * @param reportData
	 * @param filedsSet
	 * @param exportType
	 * @param exportLocation
	 * @param reportName
	 */
	public void generateReport(JasperPrint jasperPrint, String exportType, String exportLocation, String reportName,OutputStream outputStream) {
		if (EXTENSION_PDF.equalsIgnoreCase(exportType)) {
			generatePDF(jasperPrint, exportLocation, reportName, exportType,outputStream);
		} else if (EXTENSION_XLS.equalsIgnoreCase(exportType)) {
			generateXLS(jasperPrint, "Sheet1", exportLocation, reportName, exportType,outputStream);
		} else if (EXTENSION_CSV.equalsIgnoreCase(exportType)) {
			generateCSV(jasperPrint, exportLocation, reportName, exportType,outputStream);
		} else if (EXTENSION_HTML.equalsIgnoreCase(exportType)) {
			generateHTML(jasperPrint, exportLocation, reportName, exportType,outputStream);
		} else if (EXTENSION_TXT.equalsIgnoreCase(exportType)) {
			generateTXT(jasperPrint, exportLocation, reportName, exportType,outputStream);
		} else if (EXTENSION_XML.equalsIgnoreCase(exportType)) {
			generateXML(jasperPrint, exportLocation, reportName, exportType,outputStream);
		}
	}


	/**
	 * Read an excel file and spit out what we find.
	 * 
	 * @param args
	 *            Expect one argument that is the file to read.
	 * @throws IOException
	 *             When there is an error processing the file.
	 */

	/**
	 * 
	 * @param jasperReport
	 * @param reportData
	 * @param parameters
	 * @return
	 */
	private JasperPrint getJasperPrintObjectForCollectionMap(JasperReport jasperReport, List reportData, HashMap<String, Object> parameters) {
		JRMapCollectionDataSource ds = new JRMapCollectionDataSource(reportData);
		JasperPrint print = null;
		try {
			print = JasperFillManager.fillReport(jasperReport, parameters, ds);
		} catch (JRException e) {

			log.error(e.fillInStackTrace());
		}
		return print;
	}
	String WEB_ACTIVITY_NAME = "webActivityName";

	/**
	 * 
	 * @param dailyData
	 * @return
	 */
	@SuppressWarnings("unchecked")
	/*
	 * private List processWebActivityDailyData(List dailyData) { List
	 * returnData = new ArrayList();
	 * 
	 * // filling with dummy data for positions for (int i = 0; i <
	 * dailyData.size(); i++) { returnData.add(new String()); }
	 * 
	 * ListOrderedMap recordMap; String webActivityName, header, subHeader;
	 * Set<String> keys = null; int index; for (int counter = 0; counter <
	 * dailyData.size(); counter++) { recordMap = (ListOrderedMap)
	 * dailyData.get(counter);
	 * 
	 * String webActDBName = (String) recordMap.get(WEB_ACTIVITY_NAME);
	 * 
	 * if (webActDBName == null || webActDBName.isEmpty()) continue; try {
	 * webActivityName = WebActivityNames.valueOf(webActDBName)
	 * .getWebActivityName(); index =
	 * WebActivityNames.valueOf(webActDBName).getIndex(); header =
	 * WebActivityNames.valueOf(webActDBName).getHeader(); subHeader =
	 * WebActivityNames.valueOf(webActDBName) .getSubHeader(); } catch
	 * (Exception e) { continue; } if (keys == null) keys = recordMap.keySet();
	 * // adding header record and empty record if (header != null &&
	 * !header.isEmpty()) { returnData.set(index - 3, getEmptyHeaderRecord(keys,
	 * null)); returnData.set(index - 2, getEmptyHeaderRecord(keys, header)); }
	 * 
	 * // adding subHeader record and empty record if (subHeader != null &&
	 * !subHeader.isEmpty()) { if (header == null || header.isEmpty()) {
	 * returnData.set(index - 2, getEmptyHeaderRecord(keys, null)); } returnData
	 * .set(index - 1, getEmptyHeaderRecord(keys, subHeader)); }
	 * recordMap.put(WEB_ACTIVITY_NAME, webActivityName);
	 * 
	 * // setting amount only for below fields if
	 * (webActDBName.equals(WebActivityNames.a_MakePayment.name()) ||
	 * webActDBName.equals(WebActivityNames.a_UpdatePayment .name()) ||
	 * webActDBName.equals(WebActivityNames.a_DeletePayment .name())) { //
	 * nothing todo } else { recordMap.put("todayTotalpayments", null);
	 * recordMap.put("MTDTotalpayments", null);
	 * recordMap.put("PTDTotalpayments", null);
	 * recordMap.put("l30Totalpayments", null); }
	 * 
	 * returnData.set(index, recordMap); }
	 * 
	 * // calculating sum for Account Maintenance Map sumData =
	 * calculateSumforAccountMaintenance(getEmptyHeaderRecord( keys,
	 * "Total update contact information"), returnData);
	 * returnData.add(WebActivityNames.a_AddFundAcct.getIndex() - 3, sumData);
	 * returnData.add(WebActivityNames.p_apptAccepted.getIndex() - 2,
	 * getEmptyHeaderRecord(keys, null)); // remove dummy values from list for
	 * (int j = 0; j < returnData.size(); j++) { if (returnData.get(j)
	 * instanceof String) { returnData.remove(j); j--; } } return returnData; }
	 */
	/**
	 * 
	 * @param record
	 * @param returnData
	 * @return
	 */
	/*
	 * @SuppressWarnings("unchecked") Map calculateSumforAccountMaintenance(Map
	 * record, List returnData) { for (int k = 0; k < returnData.size(); k++) {
	 * Object obj = returnData.get(k); if (obj instanceof Map) { Map orderedMap
	 * = (Map) obj; String webActivityName = (String) orderedMap
	 * .get(WEB_ACTIVITY_NAME); if (webActivityName == null ||
	 * webActivityName.isEmpty()) continue; if
	 * (webActivityName.equals(WebActivityNames.a_UpdateAddress
	 * .getWebActivityName()) || webActivityName
	 * .equals(WebActivityNames.a_UpdateEmail .getWebActivityName()) ||
	 * webActivityName .equals(WebActivityNames.a_UpdatePhone
	 * .getWebActivityName()) || webActivityName
	 * .equals(WebActivityNames.a_UpdatePreferHomeEmail .getWebActivityName())
	 * || webActivityName .equals(WebActivityNames.a_UpdatePreferHomeAddress
	 * .getWebActivityName()) || webActivityName
	 * .equals(WebActivityNames.a_UpdatePreferHomePhone .getWebActivityName())
	 * || webActivityName .equals(WebActivityNames.a_UpdatePreferMobilePhone
	 * .getWebActivityName()) || webActivityName
	 * .equals(WebActivityNames.a_UpdatePreferTextMessage .getWebActivityName())
	 * || webActivityName .equals(WebActivityNames.a_UpdatePreferWorkPhone
	 * .getWebActivityName())) { for (Iterator<String> iterator =
	 * record.keySet().iterator(); iterator .hasNext();) { String key =
	 * iterator.next(); if (orderedMap.get(key) == null || !(orderedMap.get(key)
	 * instanceof Long)) continue; record.put(key, new Long((record.get(key) ==
	 * null ? 0 : ((Long) record.get(key)).longValue()) + (orderedMap.get(key)
	 * == null ? 0 : ((Long) orderedMap.get(key)) .longValue()))); } } } }
	 * return record; }
	 */
	/**
	 * 
	 * @param keys
	 * @param headerOrSubHeader
	 * @return
	 */
	private Map<String, Object> getEmptyHeaderRecord(Set<String> keys, String headerOrSubHeader) {
		Map<String, Object> orderedMap = new HashMap<String, Object>();
		for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {
			orderedMap.put(iterator.next(), null);
		}
		if (headerOrSubHeader != null && !headerOrSubHeader.isEmpty())
			orderedMap.put(WEB_ACTIVITY_NAME, headerOrSubHeader);
		return orderedMap;
	}

}
